from python.lib.heapq import heappop, heappush


class SemiDynamicRouting:
    def __init__(self, network, update_interval):
        self.network = network
        self.update_interval = update_interval  # 路径更新周期
        self.link_utilization = {}  # 链路当前利用率 {(u,v): util}

    def dynamic_route_selection(self, src, dst, traffic_volume):
        """
        基于实时链路状态的动态路由算法
        """

        # 使用A*算法优化路径搜索
        def heuristic(node):
            # 简单启发式：剩余跳数估计
            return 0  # 可替换为更复杂的估计

        heap = [(0, src, [], 0)]  # (cost+heuristic, node, path, actual_cost)
        visited = {}

        while heap:
            f_cost, u, path, g_cost = heappop(heap)
            if u in visited and visited[u] <= g_cost:
                continue
            visited[u] = g_cost

            if u == dst:
                return path

            for v in self.network.topology[u]:
                # 获取实时链路时延（考虑当前利用率）
                current_util = self.link_utilization.get((u, v), 0)
                link_delay = self.network.get_link_delay(u, v, current_util + traffic_volume)

                new_g_cost = g_cost + link_delay
                new_f_cost = new_g_cost + heuristic(v)
                heappush(heap, (new_f_cost, v, path + [(u, v)], new_g_cost))

        return None  # 无可用路径

    def update_routing(self, demand_matrix):
        """
        周期性路径更新（模拟网络控制器行为）
        """
        current_max_delay = 0
        for src in demand_matrix:
            for dst in demand_matrix[src]:
                if src == dst or demand_matrix[src][dst] <= 0:
                    continue

                # 动态选择路径
                path = self.dynamic_route_selection(src, dst, demand_matrix[src][dst])

                # 更新链路利用率
                for u, v in path:
                    self.link_utilization[(u, v)] = self.link_utilization.get((u, v), 0) + demand_matrix[src][dst]

                # 计算路径时延
                path_delay = sum(self.network.get_link_delay(u, v, self.link_utilization.get((u, v), 0))
                                 for u, v in path)
                current_max_delay = max(current_max_delay, path_delay)

        # 重置光链路配置（周期性重构）
        self.network.current_config = self.optimize_optical_config()

        return current_max_delay

    def optimize_optical_config(self):
        """
        优化光链路激活配置（贪心算法示例）
        """
        # 选择利用率最高的前K条光链路激活
        optical_utils = {(u, v): self.link_utilization.get((u, v), 0)
                         for (u, v) in self.network.optical_links}
        sorted_links = sorted(optical_utils.items(), key=lambda x: -x[1])

        # 假设最多同时激活5条光链路
        return {link for link, _ in sorted_links[:5]}